package com.jhxy.algorithm.removeduplicates;

import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;

/**
 * BitSet:
 * 用于存储一个位序列（它不是数学上的集，如果称为位向量或位数组可能更为合适)。
 * 如果需要高效地存储位序列（例如，标志），就可以使用位集。由于位集将位包装在字节里，
 * 所以使用位集要比使用Boolean对象的ArrayList高效得多。
 * 用位来表示Boolean信息，0：假，1：真
 */
public class BitSetTest {


    public static void main(String[] args) {
        BitSet bitSet = new BitSet();
        //可以将对于比特位的值设置为1，默认是0

        //将bit位2位置设置为1
        bitSet.set(2);

        //将3-5设置为1 [)左闭右开
        bitSet.set(3, 5);

        //把bit位2的位置设置为0
        bitSet.set(2, false);

        //将3-5位设置为0, [)左闭右开
        bitSet.set(3, 5, false);

        //获取值一、通过stream流来完成
        BitSet streamBitSet = new BitSet();
        streamBitSet.set(5);
        streamBitSet.set(10);
        streamBitSet.set(16);

        streamBitSet.stream().forEach(System.out::println);

        //获取值二、通过nextSetBit来完成
        //nextSetBit会返回在指定的起始索引上或之后出现的第一个被设置为true的位的索引。如果不存在这样的位，则返回-1。下面为该方法的源代码注释
        System.out.println("--------method2 nextBitSet--------");
        int k = 0;
        while ((k = streamBitSet.nextSetBit(k)) != -1) {
            System.out.println(k);
            k++;
        }


        //BitSet转数组
        System.out.println("*********bitset 转数组************");
        int[] nums = streamBitSet.stream().toArray();
        System.out.println(Arrays.toString(nums));

        //在Java中并没有bit这种数据结构，于是就通过long来完成，一个long表示64位，相当于Long可以表示0-63
        //2个long就可以表示0-127，以此类推

        /**
         * The internal field corresponding to the serialField "bits".
         */
        // private long[] words;
        //这里举几个例子，我们set(1)，那么就会算出设置的值是第几个64，这里显然就是第0个(数组从0开始)，
        // 然后将word[0]的63-1位设置为1(从0开始)，也就是从右往左的第 x % 64位设置为1。set(1)，那么words[0]应该等于 2，
        // 继续set[2]，那么words[0]应该等于4+2=6

        //面试题：对10亿个手机号码去重

        /**
         * 如int占4字节，double占8字节，这可以使得Java在不同的平台上所占类型固定，
         * 很好地保证了Java的可移植性。因此，Java中char类型固定占2个字节。(注：char类型也可以存储一个汉字)。
         *
         * 其次，String采用一种更灵活的方式进行存储。在String中，一个英文字符占1个字节，而中文字符根据编码的不同所占字节数也不同。
         * 在UTF-8编码下，一个中文字符占3个字节；而使用GBK编码时一个中文字符占2个字节。
         */

        System.out.println("----------BitSet存储10亿个手机号码-----------");
        //所以，一个手机号码11位，如果使用字符串存储的话，10亿个手机号码就占用，1M = 1,048,576字节（b）= 1024kb
        //100000000 * 11 = 1100000000字节
        //1100000000 / 1024 = 1074218 KB / 1024 = 1049 M / 1024 = 10G左右

        //分桶理论135 1111 2222
        BitSet phoneSet = new BitSet();
        phoneSet.set(11112222);
        Map<String,BitSet> map = new HashMap<>();
        //当key存在时，BitFunction一定会被执行
        BitSet bitSet135 = map.computeIfAbsent("135",m -> phoneSet);

        System.out.println(bitSet135.get(11112222));
        System.out.println(bitSet135.get(11112223));
    }
}
